﻿using Aluetjen.EmailService.Domain.Gateways;
using Aluetjen.EmailService.Domain.Models.Message;
using Aluetjen.EmailService.Domain.Models.Pipeline;
using Aluetjen.EmailService.Domain.Services;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace Aluetjen.EmailService.Domain.Tests.Services
{
    [TestClass]
    public class DispatchServiceTests : DispatchServiceTestsBase
    {
        private const string _gatewayName = "Test";

        [TestMethod]
        public void Send_Should_Dispatch_Email_To_Gateway()
        {
            SetUpMocks();

            IGatewayImpl gatewayImpl;
            Gateway gateway;
            SetUpGateway(_gatewayName, out gatewayImpl, out gateway);
            SetUpRepository();

            DispatchService service = GetInstance();

            var mail = new MailMessage();
            service.ProcessMessage(mail);

            gatewayImpl.AssertWasCalled(g => g.Send(mail), s => s.Repeat.Once());
        }

        [TestMethod]
        public void Send_Should_Not_Dispatch_Email_To_Inactive_Gateway()
        {
            SetUpMocks();

            IGatewayImpl gatewayImpl;
            Gateway gateway;
            SetUpGateway(_gatewayName, out gatewayImpl, out gateway);

            gateway.DispatchToGateway = false;

            SetUpRepository();

            DispatchService service = GetInstance();

            var mail = new MailMessage();
            service.ProcessMessage(mail);

            gatewayImpl.AssertWasNotCalled(g => g.Send(mail), s => s.Repeat.Once());
        }

        [TestMethod]
        public void Send_Should_Continue_Dispatch_If_Ignore_Failure_Is_Configured_For_Gateway()
        {
            SetUpMocks();

            IGatewayImpl gatewayImplA, gatewayImplB;
            Gateway gatewayA, gatewayB;
            SetUpGateway(_gatewayName + "A", out gatewayImplA, out gatewayA);

            gatewayA.IgnoreFailure = true;
            gatewayImplA.Stub(s => s.Send(null)).IgnoreArguments().Throw(
                new GatewayCommunicationException("Not playing ball!"));

            SetUpGateway(_gatewayName + "B", out gatewayImplB, out gatewayB);

            SetUpRepository();

            DispatchService service = GetInstance();

            var mail = new MailMessage();
            service.ProcessMessage(mail);

            gatewayImplA.AssertWasCalled(g => g.Send(mail), s => s.Repeat.Once());
            gatewayImplB.AssertWasCalled(g => g.Send(mail), s => s.Repeat.Once());
        }

        [TestMethod]
        public void Send_Should_Throw_If_Gateway_Throws()
        {
            SetUpMocks();

            IGatewayImpl gatewayImplA, gatewayImplB;
            Gateway gatewayA, gatewayB;
            SetUpGateway(_gatewayName + "A", out gatewayImplA, out gatewayA);

            gatewayImplA.Stub(s => s.Send(null)).IgnoreArguments().Throw(
                new GatewayCommunicationException("Not playing ball!"));

            SetUpGateway(_gatewayName + "B", out gatewayImplB, out gatewayB);

            SetUpRepository();

            DispatchService service = GetInstance();

            var mail = new MailMessage();

            try
            {
                service.ProcessMessage(mail);

                Assert.Fail("Exception expected!");
            }
            catch (GatewayCommunicationException)
            {
            }

            gatewayImplA.AssertWasCalled(g => g.Send(mail), s => s.Repeat.Once());
            gatewayImplB.AssertWasNotCalled(g => g.Send(mail), s => s.Repeat.Once());
        }
    }
}